﻿using System;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

using Perseus;
using Perseus.Collections;
using Perseus.Plugins;

using Hetymine.Executioner.Data;
using Hetymine.Executioner.Plugins;

namespace Hetymine.Executioner.Commands {
    public class CommandConfiguratorList : IConfiguratorList {
        private bool _IsApply = false;
        private string _Type = null;
        private EventList<IConfiguratorItem> _Items = new EventList<IConfiguratorItem>();
        private Dictionary<string, List<ICommand>> _Commands;
        private Dictionary<string, int> _SelectedIndexes = new Dictionary<string, int>();      

        public CommandConfiguratorList(Dictionary<string, List<ICommand>> commands) {
            this._Commands = commands;

            this._Items.ItemAdded += new ListChangedEventHandler<IConfiguratorItem>(_Items_ItemAdded);
            this._Items.ItemRemoved += new ListChangedEventHandler<IConfiguratorItem>(_Items_ItemRemoved);
            
            this.CanAddItem = false;
            this.CanRemoveItem = true;
        }

        private void _Items_ItemAdded(EventList<IConfiguratorItem> sender, ListEventArgs<IConfiguratorItem> e) {
            if (!this._IsApply) { return; }

            var ci = e.Item as CommandConfiguratorItem;

            this._Commands[ci.Type].Add(ci.Command);
        }
        private void _Items_ItemRemoved(EventList<IConfiguratorItem> sender, ListEventArgs<IConfiguratorItem> e) {
            if (!this._IsApply) { return; }

            var ci = e.Item as CommandConfiguratorItem;
            this._Commands[ci.Type].Remove(ci.Command);
        }

        public void FilterType(string type) {
            if (type == this._Type) { return; }

            if (type.IsEmpty() || type.Is("Unknown")) {
                this.CanAddItem = false;
                this.CanRemoveItem = true;            
            }
            else {
                this.CanAddItem = true;
                this.CanRemoveItem = true;
            }

            if (!this._Commands.ContainsKey(type)) {
                this._Commands.Add(type, new List<ICommand>());
            }

            this._IsApply = false;

            this._Items.Clear();

            if (type.IsEmpty()) {
                foreach (string key in this._Commands.Keys) {
                    foreach (ICommand command in this._Commands[key]) {
                        this._Items.Add(new CommandConfiguratorItem(key, command));
                    }
                }
            }
            else {
                foreach (ICommand command in this._Commands[type]) {
                    this._Items.Add(new CommandConfiguratorItem(type, command));
                }
            }

            // Save selected index of current type
            if (this._Type != null) {                
                this._SelectedIndexes[this._Type] = this.SelectedIndex;
            }

            // TODO: Save selected item to config for next time config window opens
            if (!this._SelectedIndexes.ContainsKey(type)) {
                this._SelectedIndexes.Add(type, -1);
            }

            // Update selected index of newely selected type
            this.SelectedIndex = this._SelectedIndexes[type];
            this._Type = type;

            this._IsApply = true;

            this.OnListChanged(EventArgs.Empty);
        }

        #region IConfiguratorList
        public IConfiguratorItem InitializeItem() {
            ICommand command = null;
            
            if (this._Type.Is("Trigger")) {
                command = new TriggerCommand();
            }
            else {
                PluginInstance<IPlugin> plugin = Executioner.PluginService[this._Type, typeof(CommandPlugin)];
                if (plugin == null) { return null; }
                CommandPlugin cp = plugin.Instance as CommandPlugin;
                if (cp.CanInitialize) {
                    command = cp.InitializeCommand();
                }
            }

            return new CommandConfiguratorItem(this._Type, command);
        }

        public IList<IConfiguratorItem> Items { get { return this._Items; } }

        public event EventHandler ListChanged;
        protected virtual void OnListChanged(EventArgs e) {
            if (this.ListChanged != null) {
                this.ListChanged(this, e);
            }
        }

        public bool CanAddItem { get; protected set; }
        public bool CanRemoveItem { get; protected set; }

        public object ListItemContent(IConfiguratorItem item) {
            TextBlock tb = new TextBlock();

            var ci = item as CommandConfiguratorItem;

            if (this._Type.IsEmpty()) {
                Bold b = new Bold(new Run("[ "));
                b.Foreground = Brushes.DarkGray;
                tb.Inlines.Add(b);

                tb.Inlines.Add(new Run(ci.Type.ToLower()));

                b = new Bold(new Run(" ]  "));
                b.Foreground = Brushes.DarkGray;
                tb.Inlines.Add(b);
            }

            if (item.Name.IsEmpty()) {
                tb.Inlines.Add(new Run("<no name set>"));
            }
            else {
                tb.Inlines.Add(new Run(item.Name));
            }

            if (ci.Command.CallStrings.Count > 0) {
                Bold b = new Bold(new Run("  ( "));
                b.Foreground = Brushes.DarkGray;
                tb.Inlines.Add(b);

                tb.Inlines.Add(new Italic(new Run(String.Join(", ", ci.Command.CallStrings.ToArray()))));

                b = new Bold(new Run(" )"));
                b.Foreground = Brushes.DarkGray;
                tb.Inlines.Add(b);
            }

            if (ci.Type == "Trigger") {
                var tc = ci.Command as TriggerCommand;
                if (tc.HasTriggers) {
                    Bold b = new Bold(new Run(" +"));
                    tb.Inlines.Add(b);
                }
            }

            return tb;
        }

        public int SelectedIndex { get; set; }

        public string ItemName { get { return "Command"; } }
        public string ListGroupBoxName { get { return "Command List"; } }
        public string EditGroupBoxName { get { return "Edit Command"; } }
        #endregion        
    }
}
